package com.ruoyi.user.filter;
import com.ruoyi.user.utils.WxJwtUtils;
import com.ruoyi.manage.domain.User;
import com.ruoyi.manage.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.List;

/**
 * 微信认证过滤器，用于处理微信相关的请求认证
 */
@Component
public class WechatAuthFilter extends OncePerRequestFilter {
    // 微信请求路径列表，用于判断是否是微信请求
    private final List<String> WX_PATHS = List.of("/userWeixin/", "/wxapi/");
    
    // 无需认证的路径，比如登录接口
    private final List<String> EXCLUDE_PATHS = List.of("/userWeixin/user/login/");

    //  微信认证令牌头
    private static String WX_TOKEN_HEADER;

    @Value("${wx.jwt.header}")
    public void setWxTokenHeader(String header) {
        WX_TOKEN_HEADER = header;
    }

    // 用户服务，用于获取用户信息
    @Autowired
    private UserServiceImpl userService;
    
    // 微信JWT工具类
    @Autowired
    private WxJwtUtils wxJwtUtils;

    /**
     * 执行过滤器的主要方法，处理微信认证逻辑
     *
     * @param request  请求对象
     * @param response 响应对象
     * @param chain    过滤链
     * @throws IOException      IO异常
     * @throws ServletException Servlet异常
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws IOException, ServletException {
        // 判断是否是微信请求，如果不是则直接放行
        if (!isWechatRequest(request) || shouldSkipAuth(request)) {
            chain.doFilter(request, response);
            return;
        }

        // 获取请求头中的微信认证令牌
        String token = request.getHeader(WX_TOKEN_HEADER);
        if (token == null) {
            // 如果令牌缺失，返回未授权错误
            sendUnauthorized(response, "微信访问凭证缺失");
            return;
        }

        try {
            // 解析微信令牌获取openid，并根据openid获取用户信息
            String openId = wxJwtUtils.parseWxToken(token);
            User user = userService.selectUserByOpenid(openId);

            if (user == null) {
                // 如果用户不存在，返回未授权错误
                sendUnauthorized(response, "微信用户不存在");
                return;
            }

            // 设置微信认证信息到SecurityContext，并放行请求
            setWechatAuthentication(user);
            chain.doFilter(request, response);
        } catch (Exception e) {
            // 如果认证过程中发生异常，返回未授权错误
            sendUnauthorized(response, "微信认证失败: " + e.getMessage());
        }
    }

    /**
     * 判断是否是微信请求
     *
     * @param request 请求对象
     * @return 如果是微信请求返回true，否则返回false
     */
    private boolean isWechatRequest(HttpServletRequest request) {
        return WX_PATHS.stream().anyMatch(path ->
                request.getRequestURI().startsWith(path));
    }
    
    /**
     * 判断是否应该跳过认证
     * 
     * @param request 请求对象
     * @return 如果应该跳过认证返回true，否则返回false
     */
    private boolean shouldSkipAuth(HttpServletRequest request) {
        String uri = request.getRequestURI();
        return EXCLUDE_PATHS.stream().anyMatch(uri::startsWith);
    }

    /**
     * 设置微信认证信息到SecurityContext
     *
     * @param user 用户对象
     */
    private void setWechatAuthentication(User user) {
        WechatAuthenticationToken authentication =
                new WechatAuthenticationToken(
                        user,
                        List.of(new SimpleGrantedAuthority("ROLE_WECHAT_USER"))
                );
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    /**
     * 发送未授权响应
     *
     * @param response 响应对象
     * @param message  错误信息
     * @throws IOException IO异常
     */
    private void sendUnauthorized(HttpServletResponse response, String message) throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        String jsonResponse = String.format("{\"code\":401,\"msg\":\"%s\"}", message);
        writer.write(jsonResponse);
        writer.flush();
    }

    /**
     * 微信认证令牌类
     */
    public static class WechatAuthenticationToken extends AbstractAuthenticationToken {
        private final User principal;

        /**
         * 构造方法，初始化微信认证令牌
         *
         * @param principal    用户对象
         * @param authorities  用户权限
         */
        public WechatAuthenticationToken(User principal, Collection<SimpleGrantedAuthority> authorities) {
            super(authorities);
            this.principal = principal;
            setAuthenticated(true);
        }

        @Override
        public Object getCredentials() {
            return null; // 微信认证无需凭证
        }

        @Override
        public Object getPrincipal() {
            return this.principal;
        }
    }
}
